home *** CD-ROM | disk | FTP | other *** search
- /*
- * selfuncs.c --
- * Selectivity functions for system catalogs and builtin types
- *
- * These routines are registered in the operator catalog in the
- * "oprrest" and "oprjoin" attributes.
- *
- * XXX check all the functions--I suspect them to be 1-based.
- */
-
- #include <stdio.h>
- #include <strings.h>
-
- #include "access/heapam.h"
- #include "access/tqual.h" /* for NowTimeQual */
- #include "utils/fmgr.h"
- #include "utils/builtins.h" /* for textout() prototype */
- #include "utils/log.h"
-
- #include "catalog/catname.h"
- #include "catalog/syscache.h"
- #include "catalog/pg_statistic.h"
-
- RcsId("$Header: /private/postgres/src/utils/adt/RCS/selfuncs.c,v 1.19 1992/01/13 02:21:26 mao Exp $");
-
- /* N is not a valid var/constant or relation id */
- #define NONVALUE(N) ((N) == -1)
-
- /*
- * generalize the test for functional index selectivity request
- */
- #define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttributeNumber)
-
- int32 getattnvals ARGS((ObjectId relid , AttributeNumber attnum ));
- int gethilokey ARGS((ObjectId relid , AttributeNumber attnum , ObjectId opid , char **high , char **low ));
-
-
- /*
- * eqsel - Selectivity of "=" for any data type.
- */
- /*ARGSUSED*/
- float64
- eqsel(opid, relid, attno, value, flag)
- ObjectId opid;
- ObjectId relid;
- AttributeNumber attno;
- char *value;
- int32 flag;
- {
- int32 nvals;
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno) || NONVALUE(relid))
- *result = 0.1;
- else {
- nvals = getattnvals(relid, (int) attno);
- if (nvals == 0)
- *result = 0.0;
- else
- *result = 1.0 / nvals;
- }
- return(result);
- }
-
- /*
- * neqsel - Selectivity of "!=" for any data type.
- */
- float64
- neqsel(opid, relid, attno, value, flag)
- ObjectId opid;
- ObjectId relid;
- AttributeNumber attno;
- char *value;
- int32 flag;
- {
- float64 result;
-
- result = eqsel(opid, relid, attno, value, flag);
- *result = 1.0 - *result;
- return(result);
- }
-
- /*
- * intltsel - Selectivity of "<" for integers.
- * Should work for both longs and shorts.
- */
- float64
- intltsel(opid, relid, attno, value, flag)
- ObjectId opid;
- ObjectId relid;
- AttributeNumber attno;
- /* XXX char *value;*/
- int32 value;
- int32 flag;
- {
- float64 result;
- char *highchar, *lowchar;
- long val, high, low, top, bottom;
- extern long atol();
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno) || NONVALUE(relid))
- *result = 1.0 / 3;
- else {
- /* XXX val = atol(value);*/
- val = value;
- gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
- if (*highchar == 'n' || *lowchar == 'n') {
- *result = 1.0/3.0;
- return (result);
- }
- high = atol(highchar);
- low = atol(lowchar);
- if ((flag & SEL_RIGHT && val < low) ||
- (!(flag & SEL_RIGHT) && val > high)) {
- int nvals;
- nvals = getattnvals(relid, (int) attno);
- if (nvals == 0)
- *result = 1.0 / 3.0;
- else
- *result = 3.0 / nvals;
- }
- else {
- bottom = high - low;
- if (bottom == 0)
- ++bottom;
- if (flag & SEL_RIGHT)
- top = val - low;
- else
- top = high - val;
- if (top > bottom)
- *result = 1.0;
- else {
- if (top == 0)
- ++top;
- *result = ((1.0 * top) / bottom);
- }
- }
- }
- return(result);
- }
-
- /*
- * intgtsel - Selectivity of ">" for integers.
- * Should work for both longs and shorts.
- */
- float64
- intgtsel(opid, relid, attno, value, flag)
- ObjectId opid;
- ObjectId relid;
- AttributeNumber attno;
- /* XXX char *value;*/
- int32 value;
- int32 flag;
- {
- float64 result;
- int notflag;
-
- if (flag & 0)
- notflag = flag & ~SEL_RIGHT;
- else
- notflag = flag | SEL_RIGHT;
- result = intltsel(opid, relid, attno, value, (int32) notflag);
- return(result);
- }
-
- /*
- * eqjoinsel - Join selectivity of "="
- */
- /*ARGSUSED*/
- float64
- eqjoinsel(opid, relid1, attno1, relid2, attno2)
- ObjectId opid;
- ObjectId relid1;
- AttributeNumber attno1;
- ObjectId relid2;
- AttributeNumber attno2;
- {
- float64 result;
- int32 num1, num2, max;
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno1) || NONVALUE(relid1) ||
- NONVALUE(attno2) || NONVALUE(relid2))
- *result = 0.1;
- else {
- num1 = getattnvals(relid1, (int) attno1);
- num2 = getattnvals(relid2, (int) attno2);
- max = (num1 > num2) ? num1 : num2;
- if (max == 0)
- *result = 1.0;
- else
- *result = 1.0 / max;
- }
- return(result);
- }
-
- /*
- * neqjoinsel - Join selectivity of "!="
- */
- float64
- neqjoinsel(opid, relid1, attno1, relid2, attno2)
- ObjectId opid;
- ObjectId relid1;
- AttributeNumber attno1;
- ObjectId relid2;
- AttributeNumber attno2;
- {
- float64 result;
-
- result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
- *result = 1.0 - *result;
- return(result);
- }
-
- /*
- * intltjoinsel - Join selectivity of "<"
- */
- /*ARGSUSED*/
- float64
- intltjoinsel(opid, relid1, attno1, relid2, attno2)
- ObjectId opid;
- ObjectId relid1;
- AttributeNumber attno1;
- ObjectId relid2;
- AttributeNumber attno2;
- {
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 3.0;
- return(result);
- }
-
- /*
- * intgtjoinsel - Join selectivity of ">"
- */
- /*ARGSUSED*/
- float64
- intgtjoinsel(opid, relid1, attno1, relid2, attno2)
- ObjectId opid;
- ObjectId relid1;
- AttributeNumber attno1;
- ObjectId relid2;
- AttributeNumber attno2;
- {
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 3.0;
- return(result);
- }
-
- /*
- * getattnvals - Retrieves the number of values within an attribute.
- *
- * Note:
- * getattnvals and gethilokey both currently use keyed
- * relation scans and amgetattr. Alternatively,
- * the relation scan could be non-keyed and the tuple
- * returned could be cast (struct X *) tuple + tuple->t_hoff.
- * The first method is good for testing the implementation,
- * but the second may ultimately be faster?!? In any case,
- * using the cast instead of amgetattr would be
- * more efficient. However, the cast will not work
- * for gethilokey which accesses stahikey in struct statistic.
- */
- int32
- getattnvals(relid, attnum)
- ObjectId relid;
- AttributeNumber attnum;
- {
- HeapTuple atp;
- int nvals;
-
- atp = SearchSysCacheTuple(ATTNUM, relid, attnum, NULL, NULL);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "getattnvals: no attribute tuple %d %d",
- relid, attnum);
- return(0);
- }
- nvals = ((struct attribute *) GETSTRUCT(atp))->attnvals;
- if (nvals > 0) return(nvals);
-
- atp = SearchSysCacheTuple(RELOID, relid, NULL, NULL, NULL);
- /* XXX -- use number of tuples as number of distinctive values
- just for now, in case number of distinctive values is
- not cached */
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "getattnvals: no relation tuple %d", relid);
- return(0);
- }
- nvals = ((RelationTupleForm) GETSTRUCT(atp))->reltuples;
- return(nvals);
- }
-
- /*
- * gethilokey - Returns a pointer to strings containing
- * the high and low keys within an attribute.
- *
- * Currently returns "0", and "0" in high and low if the statistic
- * catalog does not contain the proper tuple. Eventually, the
- * statistic demon should have the tuple maintained, and it should
- * elog() if the tuple is missing.
- *
- * XXX Question: is this worth sticking in the catalog caches,
- * or will this get invalidated too often?
- */
- gethilokey(relid, attnum, opid, high, low)
- ObjectId relid;
- AttributeNumber attnum;
- ObjectId opid;
- char **high;
- char **low;
- {
- register Relation rdesc;
- register HeapScanDesc sdesc;
- static ScanKeyEntryData key[3] = {
- { 0, StatisticRelationIdAttributeNumber, F_OIDEQ },
- { 0, StatisticAttributeNumberAttributeNumber, F_INT2EQ },
- { 0, StatisticOperatorAttributeNumber, F_OIDEQ }
- };
- Boolean isnull;
- HeapTuple tuple;
-
- rdesc = RelationNameOpenHeapRelation(StatisticRelationName);
- key[0].argument = ObjectIdGetDatum(relid);
- key[1].argument = Int16GetDatum((int16) attnum);
- key[2].argument = ObjectIdGetDatum(opid);
- sdesc = RelationBeginHeapScan(rdesc, 0, NowTimeQual,
- 3, (ScanKey) key);
- tuple = amgetnext(sdesc, 0, (Buffer *) NULL);
- if (!HeapTupleIsValid(tuple)) {
- *high = "n";
- *low = "n";
- /* XXX elog(WARN, "gethilokey: statistic tuple not found");*/
- return;
- }
- *high = textout((struct varlena *)
- amgetattr(tuple,
- InvalidBuffer,
- StatisticHighKeyAttributeNumber,
- &rdesc->rd_att,
- &isnull));
- if (isnull)
- elog(DEBUG, "gethilokey: high key is null");
- *low = textout((struct varlena *)
- amgetattr(tuple,
- InvalidBuffer,
- StatisticLowKeyAttributeNumber,
- &rdesc->rd_att,
- &isnull));
- if (isnull)
- elog(DEBUG, "gethilokey: low key is null");
- HeapScanEnd(sdesc);
- RelationCloseHeapRelation(rdesc);
- }
-
- float64
- btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid)
- ObjectId operatorObjectId, indrelid, indexrelid;
- AttributeNumber attributeNumber;
- char *constValue;
- int32 constFlag;
- int32 nIndexKeys;
- {
- float64 result;
- float64data resultData;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now simply assume it's
- * 1/3 since functions don't currently
- * have selectivity functions
- */
- resultData = 1.0 / 3.0;
- result = &resultData;
- }
- else {
- result = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)attributeNumber,
- (char*)constValue,
- (char*)constFlag);
- }
-
- if (!PointerIsValid(result))
- elog(WARN, "Btree Selectivity: bad pointer");
- if (*result < 0.0 || *result > 1.0)
- elog(WARN, "Btree Selectivity: bad value %lf", *result);
-
- return(result);
- }
-
- float64
- btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid)
- ObjectId operatorObjectId, indrelid, indexrelid;
- AttributeNumber attributeNumber;
- char *constValue;
- int32 constFlag;
- int32 nIndexKeys;
- {
- float64 temp, result;
- float64data tempData;
- HeapTuple atp;
- int npage;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now simply assume it's
- * 1/3 since functions don't currently
- * have selectivity functions
- */
- tempData = 1.0 / 3.0;
- temp = &tempData;
- }
- else {
- temp = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)attributeNumber,
- (char*)constValue,
- (char*)constFlag);
- }
- atp = SearchSysCacheTuple(RELOID, indexrelid, NULL, NULL, NULL);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "btreenpage: no index tuple %d", indexrelid);
- return(0);
- }
-
- npage = ((RelationTupleForm) GETSTRUCT(atp))->relpages;
- result = (float64)palloc(sizeof(float64data));
- *result = *temp * npage;
- return(result);
- }
-
- float64
- rtsel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid)
- ObjectId operatorObjectId, indrelid, indexrelid;
- AttributeNumber attributeNumber;
- char *constValue;
- int32 constFlag;
- int32 nIndexKeys;
- {
- return (btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
- }
-
- float64
- rtnpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid)
- ObjectId operatorObjectId, indrelid, indexrelid;
- AttributeNumber attributeNumber;
- char *constValue;
- int32 constFlag;
- int32 nIndexKeys;
- {
- return (btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
- }
-